
# 设置默认flash位置

set flash_addr {
    AC      0x40022000
    KEY     0x40022004
    OPTKEY  0x40022008
    STS     0x4002200C
    CTRL    0x40022010
    ADD     0x40022014
    OB      0x4002201C
    WRP     0x40022020
    ECC     0x40022024
    RDN     0x4002202C
    CAHR    0x40022030

    # 一些操作数据
    UNLOCK_KEY1 0x45670123
    UNLOCK_KEY2 0xcdef89ab

    PAGE_SIZE       0x800
    FLASH_END       0x08040000
    FLASH_ADDR     0x08000000
}


    # 一些flash的信息, 1个page大小2kB

# global flash_addr

# echo $::flash_addr(KEY)
# echo $::flash_addr(UNLOCK_KEY1)
# echo 22222222222222222

# proc xxxx { } {
#     echo $::flash_addr(KEY)
#     echo $::flash_addr(UNLOCK_KEY1)
#     echo 333333333
# }


proc xflash-is-unlock { } {
    set ctrl [mrw $::flash_addr(CTRL)]
    return [expr $ctrl&1]
}

proc xflash-busy { } {
    set ctrl [mrw $::flash_addr(STS)]
    return [expr $ctrl&1]
}

# 需要解锁
proc xflash-unlock {} {
    echo "flash unlock!"
    #echo $::flash_addr(KEY) $::flash_addr(UNLOCK_KEY1)
    mww $::flash_addr(KEY) $::flash_addr(UNLOCK_KEY1)
    mww $::flash_addr(KEY) $::flash_addr(UNLOCK_KEY2)
    mmw $::flash_addr(CTRL) 0x01 0x00
    set x 0
    while ([xflash-is-unlock]==0) {
        #等待解锁
        after 200;
        incr x
        if $x>10 {
            break
        }
    }
    return [xflash-is-unlock]
}

proc xflash-busy-wait { } {
    set x 0
    while [xflash-busy] {
        after 200;
        incr x
        if $x>10 {
            return 1
        }
    }
    return 0
}

proc xflash-erase-page {addr} {
    # 需要检查是否正在执行闪存操作
    if [xflash-busy-wait] {
        echo "wait timeout!"
        return 0
    }

    # 结束等待
    # 开启页擦除,PER置为1
    mmw $::flash_addr(CTRL) 0x2 0x3

    #把页起始地址写入FLASH_ADD
    mww $::flash_addr(ADD) $addr

    #CTRL.START = 1
    mmw $::flash_addr(CTRL) 0x40 0

    #等待BUSY==0
    xflash-busy-wait
    return 1
}

# 擦除指令
proc xflash-erase {addr {end -1}} {
    while 1 {
        xflash-erase-page $addr
        incr addr $::flash_addr(PAGE_SIZE)
        if $addr>$end {
            break
        }
    }
}

proc xflash-program-start {} {
    # 启用编程模式,CTRL.PG = 1
    # 其实在 xflash-busy-wait 后就启动了
    mmw $::flash_addr(CTRL) 0x1 0x3
}

proc xflash-program {addr dat} {
    mww $addr $dat
}

proc xflash-program-end {} {
    # 关闭编程模式
    mmw $::flash_addr(CTRL) 0x0 0x3
}

proc xflash-erase-all {} {
    # 现在测试256KB的flash
    set addr $::flash_addr(FLASH_ADDR)
    set max_addr $::flash_addr(FLASH_END)
    set count 0
    while $addr<$max_addr {

        # 每100次擦除.则输出一个信息
        incr count
        if $count>100 {
            set hex [format "0x%08x" $addr]
            echo "erase $hex"
            set count 0
        }

        xflash-erase-page $addr
        incr addr $::flash_addr(PAGE_SIZE)
        # 不会用这脚本.需要break退出
        if $addr>=$max_addr {
            break;
        }
    }
}

proc xflash-dump-all {} {
    set addr $::flash_addr(FLASH_ADDR)
    set max_addr $::flash_addr(FLASH_END)
    #打开临时的导出文件
    set f [open "dump.txt" "w+"]

    while $addr<$max_addr {
        set v [mrw $addr]
        set hex [format "mww 0x%08X 0x%08X" $addr $v]
        puts $f $hex
        incr addr 0x4
        if $addr>=$max_addr {
            echo "dump end!";
            break;
        }
    }

    #关闭文件
    close $f
}

#flash 读写需要注意以下几种情况
#   擦除操作需要关闭编程模式
#   编程模式需要关闭擦除操作


#有关数据写入
#   可利用利用外部脚本生成tcl数据
#   然后执行tcl数据脚本写入目标调试器